/*
 Problem Description
Pass a year learning in Hangzhou, yifenfei arrival hometown Ningbo at finally. Leave Ningbo one year, yifenfei have many people to meet. Especially a good friend Merceki.
Yifenfei’s home is at the countryside, but Merceki’s home is in the center of city. So yifenfei made arrangements with Merceki to meet at a KFC. There are many KFC in Ningbo, they want to choose one that let the total time to it be most smallest. 
Now give you a Ningbo map, Both yifenfei and Merceki can move up, down ,left, right to the adjacent road by cost 11 minutes.
Input
The input contains multiple test cases.
Each test case include, first two integers n, m. (2<=n,m<=200). 
Next n lines, each line included m character.
‘Y’ express yifenfei initial position.
‘M’    express Merceki initial position.
‘#’ forbid road;
‘.’ Road.
‘@’ KCF
Output
For each test case output the minimum total time that both yifenfei and Merceki to arrival one of KFC.You may sure there is always have a KFC that can let them meet.
Sample Input
4 4
Y.#@
....
.#..
@..M
4 4
Y.#@
....
.#..
@#.M
5 5
Y..@.
.#...
.#...
@..M.
#...#
Sample Output
66
88
66
 */
package com.yuan.algorithms.practice201506;

import java.util.Scanner;



class Node {
	int x;
	int y;
	int currentTime;//当前使用时间
	
	public Node(int x, int y, int currentTime) {
		this.x = x;
		this.y = y;
		this.currentTime = currentTime;
	}
}


class QueueArray {

	private static final int CAP = 10;// 队列默认大小
	private Object[] elements;// 数据元素数组
	private int capacity;// 数组的大小
	private int front;// 队首指针
	private int rear;// 队尾指针

	public QueueArray() {
		this(CAP);
	}

	public QueueArray(int cap) {
		capacity = cap + 1;//数组长度加1，用于区分队列满的情况
		elements = new Object[capacity];
		front = rear = 0;
	}

	/**
	 * 返回队列大小
	 * 
	 * @return
	 */
	public int getSize() {
		return (rear - front + capacity) % capacity;
	}

	/**
	 * 判断队列是否为空
	 * 
	 * @return
	 */
	public boolean isEmpty() {
		return front == rear;
	}

	/**
	 * 向队列添加数据
	 * @param e
	 */
	public void add(Object e) {
		// 判断队列是否存满了
		if (getSize() == capacity - 1) {
			expandSpace();// 扩展队列
		}
		elements[rear] = e;
		rear = (rear + 1) % capacity;
	}

	/**
	 * 扩展队列容量
	 */
	private void expandSpace() {
		Object[] temp = new Object[elements.length*2 - 1];//数组容量增大一倍
		int i = front;
		int j = 0;
		//将从front开始到rear前一个存储单元的元素复制到新数组
		while(i!=rear) {
			temp[j++] = elements[i];
			i = (i + 1) % capacity;
		}
		elements = temp;
		capacity = elements.length;
		front = 0;
		rear = j;//设置新的队尾指针
	}

	/**
	 * 队首元素出队
	 * @return
	 * @throws Exception
	 */
	public Object poll() throws Exception{
		if (isEmpty()) {
			throw new Exception("错误：队列为空");
		}
		Object obj = elements[front];
		elements[front] = null;//删除原来的数据
		front = (front+1)%capacity;//更新队首指针
		return obj;
	}
	
	/**
	 * 取队首元素（不删除元素）
	 * @return
	 * @throws Exception
	 */
	public Object peek() throws Exception{
		if (isEmpty()) {
			throw new Exception("错误：队列为空");
		}
		return elements[front];
	}
}

public class 广搜_双向搜索 {

	static int n, m;
	static char[][] map;
	static boolean[][] mark;
	static final int[] var = {1,0,0,1,-1,0,0,-1};
	static int[][] resultY;
	static int[][] resultM;
	public static void main(String[] args) throws Exception {
		Scanner sc = new Scanner(System.in);
		while(sc.hasNext()) {
			n = sc.nextInt();
			m = sc.nextInt();
			map = new char[m][n];
			mark = new boolean[m][n];
			resultY = new int[m][n];
			resultM = new int[m][n];
			int[] startY = new int[2];
			int[] startM = new int[2];
			for (int i = 0; i < n; i++) {
				String a = sc.next();
				for (int j = 0; j < m; j++) {
					map[j][i] = a.charAt(j);
					if (map[j][i]=='Y') {
						startY[0] = j;
						startY[1] = i;
					}else if (map[j][i]=='M') {
						startM[0] = j;
						startM[1] = i;
					}
				}
			}
//			Node wayY = bfs(startY, -1, -1);
//			Node wayM = bfs(startM, -1, -1);
//			if (wayY.x == wayM.x && wayY.y == wayM.y) {
//				System.out.println(wayY.currentTime + wayM.currentTime);
//			} else {
//				int sum1 = 0, sum2 = 0;
//				Node wayY2 = bfs(startY,wayM.x, wayM.y);
//				sum1 = wayY2.currentTime + wayM.currentTime;
//				Node wayM2 = bfs(startM, wayY.x, wayY.y);
//				sum2 = wayM2.currentTime + wayY.currentTime;
//				if (sum1<sum2) {
//					System.out.println(sum1);
//				}else {
//					System.out.println(sum2);
//				}
//			}
			bfs(startY,0);
			bfs(startM,1);
			int sum = 0;
			int min = 0xffffff;
			for (int i = 0; i < n; i++) {
				for (int j = 0; j < m; j++) {
					if (resultY[j][i] > 0 && resultM[j][i] > 0) {
						sum = resultY[j][i] + resultM[j][i];
						if (sum<min) {
							min = sum;
						}
					}
				}
			}
			System.out.println(min);
		}
	}
	private static void bfs(int[] start, int k) throws Exception {
		QueueArray queue = new QueueArray();
		Node origin = new Node(start[0], start[1], 0);
		queue.add(origin);
		while(!queue.isEmpty()) {
			Node temp = (Node) queue.poll();
			if (map[temp.x][temp.y]=='@') {
//				mark = new boolean[m][n];
//				return temp;
				if (k==0) {
					resultY[temp.x][temp.y] = temp.currentTime; 
				}else {
					resultM[temp.x][temp.y] = temp.currentTime; 
				}
				//System.out.println(result[temp.x][temp.y]+"   x..y:"+temp.x+" "+temp.y+"   time:"+temp.currentTime);
			}
			for (int i = 0; i < 4; i++) {
				int newX = temp.x+var[i*2];
				int newY = temp.y+var[i*2+1];
				//判断下标是否越界
				boolean indexJudge = (newX>=0 && newX<map.length) && (newY>=0 && newY<map[0].length);
				if (!indexJudge) {
					continue;
				}
				//如果已经进入过该地区，则舍弃
				if (mark[newX][newY]) {
					continue;
				}
				//判断该位置是否可以通过
				boolean mapJudge = map[newX][newY] != '#';
				if (mapJudge) {
					queue.add(new Node(newX, newY, temp.currentTime+11));
					mark[temp.x][temp.y] = true; //标记以搜索过该地区
				}
			}
		}
		mark = new boolean[m][n];
//		return new Node(-1, -1, -1);
	}
	
}
